package com.gcloud.mesh.distributedSchedule.evaluateFactor;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.gcloud.mesh.distributedSchedule.ClusterAvailableResource;
import com.gcloud.mesh.distributedSchedule.ICluster;
import com.gcloud.mesh.distributedSchedule.IEvaluateFactor;
import com.gcloud.mesh.distributedSchedule.application.Application;

/**
 * 效能评价函数
 */
public class EfficiencyFactor extends EvaluateFactor implements IEvaluateFactor {

    public String nameId = "efficiency_factor";

    // 各个资源对功耗的影响因子,CPU对功耗影响最大，其他次之
    private double cpuRate = 1.0;
    private double memRate = 0.6;
    private double storageRate = 0.3;
    private double bandWidthRate = 0.3;

    /**
     * 能效评价，基于集群的负载来评估，HIGH 70%   MEDIUM 50%    LOW  30%
     * 应用可能只迁移到部分集群，那么我们只评估迁移到的集群
     * @param scheduleAppList  要调度的应用
     * @param targetClusters   app要调度到的目标集群
     * @param clusterIds       应用要调度到的集群id列表，顺序和 scheduleAppList 保持一致
     * @return
     */
    @Override
    public evalResult evaluate(Application[] scheduleAppList, ConcurrentHashMap<String, ICluster> targetClusters, String[] clusterIds) {
        evalResult er = new evalResult(nameId);
        HashMap<String, Set<Integer>> cltSort = this.sort(clusterIds);

        // 这里app很可能分配到多个集群，我们会对每个集群都进行评估，只要有一个集群的资源使用超出安全范围（安全范围可以设置在集群对象里），
        // 就认为不合格，score则根据权重，对所有集群的统计分数进行累加.
        for (String cltId : cltSort.keySet()) {

            HashSet<Application> appList = new HashSet<>();
            for (Integer i : cltSort.get(cltId)) {
                // 生成迁移到同一个集群的所有app的列表
                appList.add(scheduleAppList[i.intValue()]);
                ICluster target = targetClusters.get(cltId);
                ClusterAvailableResource restRes = target.getAvailResource((Application[]) appList.toArray());
                ClusterAvailableResource totalRes = target.getTotalResource();
                if (er.qualified) {
                    if (restRes.availBandWidth < 0 || restRes.availCpuCores < 0 ||
                            restRes.availMemSpace < 0 || restRes.availStorageSpace< 0) {
                        er.qualified = false;
                    }
                }
                double loadRate = target.getEfficientLoadRate();
                // cpu资源使用的比率
                double cpuRatio = ((totalRes.availCpuCores - restRes.availCpuCores) / totalRes.availCpuCores) * 100;
                // target.getEfficientLoadRate() 返回最佳能效负载，默认是70%，此公式把预测负载、设置的最佳能效负载以及设备的能效系数联系起来，
                // 得分越高，则越接近最佳负载和高效硬件
                /**
                 * 性能值计算模型：   核心思路是计算负载离最高效能负载70%的偏离程度,越接近，越高分，否则越低分
                 *           100 - (70 - 安全负载系数*100) - |cpu使用百分百 - 70|
                 */
                double cpu = (100 - (70 - loadRate * 100) - Math.abs(cpuRatio - 70))
                                * this.cpuRate;

                double memRatio = ((totalRes.availMemSpace - restRes.availMemSpace) / totalRes.availMemSpace) * 100;
                double mem = (100 - (70 - loadRate * 100) - Math.abs(memRatio - 70))
                                * this.memRate;

                double storageRatio = ((totalRes.availStorageSpace - restRes.availStorageSpace) / totalRes.availStorageSpace) * 100;
                double storage = (100 - (70 - loadRate * 100) - Math.abs(storageRatio - 70))
                                * this.storageRate;

                double bandWidthRatio = ((totalRes.availBandWidth - restRes.availBandWidth) / totalRes.availBandWidth) * 100;
                double bandWidth = (100 - (70 - loadRate * 100) - Math.abs(bandWidthRatio - 70))
                                * this.bandWidthRate;

                er.score += (cpu + mem + storage + bandWidth) * target.getEfficientValue(null);
            }
        }

        return er;
    }
}
